package com.quran.labs.androidquran.util; import android.support.annotation.NonNull; import android.util.Pair; import com.quran.labs.androidquran.common.QariItem; import com.quran.labs.androidquran.data.QuranInfo; import java.io.File; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import io.reactivex.Observable; import io.reactivex.ObservableSource; import io.reactivex.Single; import io.reactivex.functions.Function; import io.reactivex.schedulers.Schedulers; public class AudioManagerUtils { private static String padSuraNumber(int number) { return number < 10 ? "00" + number : number < 100 ? "0" + number : String.valueOf(number); } private static Map<QariItem, QariDownloadInfo> sCache = new ConcurrentHashMap<>(); public static void clearCache() { sCache.clear(); } public static void clearCacheKeyForSheikh(QariItem qariItem) { sCache.remove(qariItem); } @NonNull public static Single<List<QariDownloadInfo>> shuyookhDownloadObservable( final String basePath, List<QariItem> qariItems) { return Observable.fromIterable(qariItems) .flatMap(new Function<QariItem, ObservableSource<QariDownloadInfo>>() { @Override public ObservableSource<QariDownloadInfo> apply(QariItem item) throws Exception { QariDownloadInfo cached = sCache.get(item); if (cached != null) { return Observable.just(cached); } File baseFile = new File(basePath, item.getPath()); return !baseFile.exists() ? Observable.just(new QariDownloadInfo(item)) : item.isGapless() ? getGaplessSheikhObservable(baseFile, item).toObservable() : getGappedSheikhObservable(baseFile, item).toObservable(); } }) .doOnNext(qariDownloadInfo -> sCache.put(qariDownloadInfo.qariItem, qariDownloadInfo)) .toList() .subscribeOn(Schedulers.io()); } @NonNull private static Single<QariDownloadInfo> getGaplessSheikhObservable( final File path, final QariItem qariItem) { return Observable.range(1, 114) .map(sura -> new SuraFileName(sura, new File(path, padSuraNumber(sura) + ".mp3"))) .filter(sf -> sf.file.exists()) .map(sf -> sf.sura) .toList() .map(suras -> new QariDownloadInfo(qariItem, suras)); } @NonNull private static Single<QariDownloadInfo> getGappedSheikhObservable( final File basePath, final QariItem qariItem) { return Observable.range(1, 114) .map(sura -> new SuraFileName(sura, new File(basePath, String.valueOf(sura)))) .filter(suraFile -> suraFile.file.exists()) .map(sf -> new Pair<>(sf.sura, sf.file.listFiles().length >= QuranInfo.SURA_NUM_AYAHS[sf.sura - 1])) .toList() .map(downloaded -> QariDownloadInfo.withPartials(qariItem, downloaded)); } private static class SuraFileName { public final int sura; public final File file; SuraFileName(int sura, File file) { this.sura = sura; this.file = file; } } }